"""
验证服务
"""

import os
import hashlib
from pathlib import Path
from typing import  List, Dict, Any, Optional, Tuple
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from models.execution import Execution
from models.repository import Repository
from models.task import Task
from models.file import File
from services.git_service import git_service
from utils.logger import get_logger

logger = get_logger(__name__)


class VerificationService:
    """验证服务"""

    def __init__(self):
        self.git_service = git_service

    async def verify_sync_result(
        self,
        execution_id: int,
        db: AsyncSession
    ) -> List[Dict[str, Any]]:
        """验证同步结果"""
        try:
            # 获取执行记录
            execution = await db.get(Execution, execution_id)
            if not execution:
                raise ValueError(f"执行记录不存在: {execution_id}")

            # 获取任务信息
            task = await db.get(Task, execution.task_id)
            if not task:
                raise ValueError(f"任务不存在: {execution.task_id}")

            verification_results = []

            # 验证每个目标仓库
            for target_result in execution.target_results:
                if target_result.get("status") != "success":
                    # 跳过失败的仓库
                    continue

                repo_id = target_result.get("repo_id")
                if not repo_id:
                    continue

                verification_result = await self._verify_repository(
                    repo_id=repo_id,
                    execution=execution,
                    task=task,
                    db=db
                )

                verification_results.append(verification_result)

            # 更新执行记录的验证结果
            execution.verification_results = verification_results
            await db.commit()

            logger.info(
                "同步结果验证完成",
                execution_id=execution_id,
                verified_repos=len(verification_results)
            )

            return verification_results

        except Exception as e:
            logger.error(
                "同步结果验证失败",
                execution_id=execution_id,
                error=str(e)
            )
            raise

    async def _verify_repository(
        self,
        repo_id: int,
        execution: Execution,
        task: Task,
        db: AsyncSession
    ) -> Dict[str, Any]:
        """验证单个仓库"""
        try:
            # 获取目标仓库信息
            target_repo = await db.get(Repository, repo_id)
            if not target_repo:
                return {
                    "repo_id": repo_id,
                    "repo_name": "未知仓库",
                    "status": "error",
                    "error": "仓库不存在"
                }

            # 获取目标分支
            target_branch = task.get_branch_mapping(repo_id)
            if not target_branch:
                target_branch = execution.branch_mapping.get("source_branch", "main")

            verification_result = {
                "repo_id": repo_id,
                "repo_name": target_repo.name,
                "status": "success",
                "target_branch": target_branch,
                "commit_check": None,
                "file_check": None,
                "overall_status": "success"
            }

            # 1. 验证Commit ID
            commit_check = await self._verify_commit_id(
                target_repo=target_repo,
                target_branch=target_branch,
                expected_commit=target_result.get("commit") if target_result else execution.source_commit
            )
            verification_result["commit_check"] = commit_check

            # 2. 验证文件内容
            if task.files:
                file_check = await self._verify_files(
                    target_repo=target_repo,
                    target_branch=target_branch,
                    file_ids=task.get_file_ids(),
                    db=db
                )
                verification_result["file_check"] = file_check
            else:
                verification_result["file_check"] = {
                    "status": "skipped",
                    "message": "没有配置附加文件"
                }

            # 3. 计算总体验证状态
            if commit_check.get("status") == "failure":
                verification_result["overall_status"] = "failure"
            elif file_check and file_check.get("status") == "failure":
                verification_result["overall_status"] = "partial_failure"

            return verification_result

        except Exception as e:
            logger.error(
                "仓库验证失败",
                repo_id=repo_id,
                error=str(e)
            )
            return {
                "repo_id": repo_id,
                "repo_name": "未知仓库",
                "status": "error",
                "error": str(e),
                "overall_status": "error"
            }

    async def _verify_commit_id(
        self,
        target_repo: Repository,
        target_branch: str,
        expected_commit: str
    ) -> Dict[str, Any]:
        """验证Commit ID"""
        try:
            if not expected_commit:
                return {
                    "status": "skipped",
                    "message": "没有期望的Commit ID"
                }

            # 获取目标仓库的当前Commit ID
            repo_cache_dir = self.git_service._get_cache_dir(f"verify_{target_repo.id}")
            actual_commit = await self.git_service.get_commit_id(repo_cache_dir, target_branch)

            if not actual_commit:
                return {
                    "status": "failure",
                    "message": "无法获取目标仓库Commit ID",
                    "expected": expected_commit,
                    "actual": None
                }

            # 比较Commit ID
            if actual_commit == expected_commit:
                return {
                    "status": "success",
                    "message": "Commit ID验证通过",
                    "expected": expected_commit,
                    "actual": actual_commit
                }
            else:
                return {
                    "status": "failure",
                    "message": "Commit ID不匹配",
                    "expected": expected_commit,
                    "actual": actual_commit
                }

        except Exception as e:
            logger.error(
                "Commit ID验证失败",
                repo_id=target_repo.id,
                target_branch=target_branch,
                error=str(e)
            )
            return {
                "status": "error",
                "message": f"Commit ID验证失败: {str(e)}",
                "expected": expected_commit,
                "actual": None
            }

    async def _verify_files(
        self,
        target_repo: Repository,
        target_branch: str,
        file_ids: List[int],
        db: AsyncSession
    ) -> Dict[str, Any]:
        """验证文件内容"""
        try:
            if not file_ids:
                return {
                    "status": "skipped",
                    "message": "没有配置文件"
                }

            # 获取文件信息
            stmt = select(File).where(File.id.in_(file_ids))
            result = await db.execute(stmt)
            files = result.scalars().all()

            if not files:
                return {
                    "status": "skipped",
                    "message": "没有找到配置的文件"
                }

            verification_results = []
            repo_cache_dir = self.git_service._get_cache_dir(f"verify_{target_repo.id}")

            for file in files:
                file_result = await self._verify_single_file(
                    file=file,
                    target_repo=target_repo,
                    target_branch=target_branch,
                    repo_cache_dir=repo_cache_dir
                )
                verification_results.append(file_result)

            # 统计验证结果
            total_files = len(verification_results)
            success_files = len([r for r in verification_results if r.get("status") == "success"])
            failed_files = total_files - success_files

            overall_status = "success" if failed_files == 0 else "failure"

            return {
                "status": overall_status,
                "message": f"文件验证完成 ({success_files}/{total_files} 通过)",
                "files_checked": total_files,
                "files_passed": success_files,
                "files_failed": failed_files,
                "file_results": verification_results
            }

        except Exception as e:
            logger.error(
                "文件验证失败",
                repo_id=target_repo.id,
                target_branch=target_branch,
                error=str(e)
            )
            return {
                "status": "error",
                "message": f"文件验证失败: {str(e)}",
                "files_checked": 0,
                "files_passed": 0,
                "files_failed": 0
            }

    async def _verify_single_file(
        self,
        file: File,
        target_repo: Repository,
        target_branch: str,
        repo_cache_dir: Path
    ) -> Dict[str, Any]:
        """验证单个文件"""
        try:
            # 构建目标文件路径
            target_file_path = repo_cache_dir / file.target_path.lstrip("/")

            if not target_file_path.exists():
                return {
                    "file_id": file.id,
                    "file_name": file.name,
                    "target_path": file.target_path,
                    "status": "failure",
                    "message": "文件不存在"
                }

            # 计算文件的MD5哈希
            with open(target_file_path, "rb") as f:
                actual_hash = hashlib.md5(f.read()).hexdigest()

            # 获取期望的哈希（如果存储了的话）
            expected_hash = file.file_hash

            if expected_hash and actual_hash != expected_hash:
                return {
                    "file_id": file.id,
                    "file_name": file.name,
                    "target_path": file.target_path,
                    "status": "failure",
                    "message": "文件内容不匹配",
                    "expected_hash": expected_hash,
                    "actual_hash": actual_hash
                }

            return {
                "file_id": file.id,
                "file_name": file.name,
                "target_path": file.target_path,
                "status": "success",
                "message": "文件验证通过",
                "file_size": target_file_path.stat().st_size,
                "file_hash": actual_hash
            }

        except Exception as e:
            logger.error(
                "单文件验证失败",
                file_id=file.id,
                file_name=file.name,
                error=str(e)
            )
            return {
                "file_id": file.id,
                "file_name": file.name,
                "target_path": file.target_path,
                "status": "error",
                "message": f"文件验证失败: {str(e)}"
            }

    async def verify_before_sync(
        self,
        task_id: int,
        db: AsyncSession
    ) -> Dict[str, Any]:
        """同步前验证"""
        try:
            # 获取任务信息
            task = await db.get(Task, task_id)
            if not task:
                raise ValueError(f"任务不存在: {task_id}")

            verification_result = {
                "task_id": task_id,
                "task_name": task.name,
                "status": "success",
                "checks": {}
            }

            # 1. 验证源代码库
            source_repo = await db.get(Repository, task.source_repo_id)
            if not source_repo:
                verification_result["status"] = "failure"
                verification_result["checks"]["source_repo"] = {
                    "status": "failure",
                    "message": "源代码库不存在"
                }
                return verification_result

            # 测试源代码库连接
            try:
                source_test = await self.git_service.test_connection(source_repo)
                verification_result["checks"]["source_repo"] = {
                    "status": "success",
                    "message": "源代码库连接正常",
                    "branches": source_test.get("branches", []),
                    "last_commit": source_test.get("last_commit")
                }
            except Exception as e:
                verification_result["status"] = "failure"
                verification_result["checks"]["source_repo"] = {
                    "status": "failure",
                    "message": f"源代码库连接失败: {str(e)}"
                }
                return verification_result

            # 2. 验证目标代码库
            target_repos = []
            for repo_info in task.target_repos:
                repo_id = repo_info.get("id")
                if not repo_id:
                    continue

                target_repo = await db.get(Repository, repo_id)
                if not target_repo:
                    verification_result["checks"][f"target_repo_{repo_id}"] = {
                        "status": "failure",
                        "message": "目标代码库不存在"
                    }
                    continue

                try:
                    target_test = await self.git_service.test_connection(target_repo)
                    verification_result["checks"][f"target_repo_{repo_id}"] = {
                        "status": "success",
                        "message": "目标代码库连接正常",
                        "repo_name": target_repo.name,
                        "branches": target_test.get("branches", [])
                    }
                    target_repos.append(target_repo)
                except Exception as e:
                    verification_result["status"] = "failure"
                    verification_result["checks"][f"target_repo_{repo_id}"] = {
                        "status": "failure",
                        "message": f"目标代码库连接失败: {str(e)}"
                    }

            # 3. 验证分支配置
            source_branch = task.branch_mapping.get("source_branch")
            if not source_branch:
                verification_result["checks"]["branch_config"] = {
                    "status": "failure",
                    "message": "源分支配置缺失"
                }
                verification_result["status"] = "failure"
                return verification_result

            # 检查源分支是否存在
            if source_branch not in verification_result["checks"]["source_repo"].get("branches", []):
                verification_result["checks"]["branch_config"] = {
                    "status": "failure",
                    "message": f"源分支 '{source_branch}' 不存在"
                }
                verification_result["status"] = "failure"
                return verification_result

            verification_result["checks"]["branch_config"] = {
                "status": "success",
                "message": "分支配置正常",
                "source_branch": source_branch
            }

            # 4. 验证文件配置
            if task.files:
                stmt = select(File).where(File.id.in_(task.get_file_ids()))
                result = await db.execute(stmt)
                files = result.scalars().all()

                verification_result["checks"]["files"] = {
                    "status": "success",
                    "message": f"文件配置正常 ({len(files)} 个文件)",
                    "file_count": len(files)
                }
            else:
                verification_result["checks"]["files"] = {
                    "status": "success",
                    "message": "没有配置附加文件"
                }

            logger.info(
                "同步前验证完成",
                task_id=task_id,
                status=verification_result["status"]
            )

            return verification_result

        except Exception as e:
            logger.error(
                "同步前验证失败",
                task_id=task_id,
                error=str(e)
            )
            return {
                "task_id": task_id,
                "status": "error",
                "error": str(e)
            }


# 全局验证服务实例
verification_service = VerificationService()